package util.methods;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.TreeMap;
import java.util.TreeSet;

import assem.DBConn;
import jpave.dataholders.GlobalSettings;
import util.Debug.ErrorReport;

public class HostsCfg 
{
	static public String host = ""; // worked non-static but lots of messages.
	static public String user = "";
	static public String port = "";
	static public String pass = "";
	static public String host() {return host;}
	static public String user() {return user;}
	static public String pass() {return pass;}
	private boolean isLocalHost = false;
	
	private static TreeSet<String> localHostAliases = new TreeSet<String>();
	
	public static TreeMap<String,String> otherParams = new TreeMap<String,String>();
	final String CAP3_DEF = PaveProps.getExtDir() + "/CAP3/cap3";
	final String HOSTS = GlobalSettings.HOSTS;
	
	public HostsCfg() 
	{	
		try
		{
			if (host.equals(""))
			{
				File f = new File(HOSTS);
				if (!f.isFile())
				{
					System.err.println("Can't find " + HOSTS);
					System.exit(0);
				}
				host="localhost"; //default
				loadHOSTS(f);
				checkLocalHost();
				checkDBConnect();
				getBlastPath();
			}
		}
		catch(Exception e){ErrorReport.die("Error reading HOSTS.cfg!!");}
	}
	// Used by the applets. It doesn't do localhost checks.
	public HostsCfg(String host, String user, String pass)
	{
		this.host = host;
		this.user = user;
		this.pass = pass;
		String[] f2 = host.split(":");
		if (f2.length == 2)
		{
			host = f2[0];
			port = f2[1];
		}
		isLocalHost = false;
		if (!DBConn.checkMysqlServer(host, user, pass))
		{
			System.err.println("Unable to connect to MySQL server (host:" + host + ", user:" + user + " pass:" + pass);
			try
			{
				Thread.sleep(10000);
			}
			catch(Exception stupid){}
		}
	}
	private void loadHOSTS(File f) throws Exception
	{
		BufferedReader br = new BufferedReader(new FileReader(f));
		TreeMap<String,String> curSec = new TreeMap<String,String>();
		TreeSet<String> seen = new TreeSet<String>();
		while (br.ready())
		{	
			String line = br.readLine();
			line = line.replaceAll("#.*","");
			line += " "; // so the split works right 
			String[] fields = line.split("=");
			if (fields.length != 2) continue;
			
			String key = fields[0].trim();
			String val = fields[1].trim();
			
			key = key.replaceFirst("PAVE_", "DB_");

			if (seen.contains(key.toLowerCase()))
			{
				System.err.println("Duplicated parameter " + key);
				System.err.println("HOSTS.cfg can only have one set of parameters");
				System.exit(0);
			}
			seen.add(key.toLowerCase());
			if (key.equalsIgnoreCase("db_host"))
			{
				host = val;
				String[] f2 = host.split(":");
				if (f2.length == 2)
				{
					host = f2[0];
					port = f2[1];
				}
			}
			else if (key.equalsIgnoreCase("db_port")) port = val;
			else if (key.equalsIgnoreCase("db_user")) user = val;
			else if (key.equalsIgnoreCase("db_password")) pass = val;
			else otherParams.put(key, val);
		}
	}

	public String hostPlusPort(String host, String port)
	{
		if (!port.equals(""))
		{
			return host + ":" + port;
		}
		return host;
	}

	// Find all the aliases for the current machine, and see if
	// the specified host is one of them
	private void checkLocalHost()
	{
		try
		{
			localHostAliases.add("localhost");
			if (host.equalsIgnoreCase("localhost"))
			{
				host = "localhost";
				isLocalHost = true;
			}
			String hostName = getHostName();
			localHostAliases.add(hostName);
			if (hostName.equalsIgnoreCase(host))
			{
				isLocalHost = true;
			}
			hostName = java.net.InetAddress.getLocalHost().getHostName();
			localHostAliases.add(hostName);
			if (hostName.equalsIgnoreCase(host))
			{
				isLocalHost = true;
			}		
			hostName = java.net.InetAddress.getLocalHost().getCanonicalHostName();
			localHostAliases.add(hostName);
			if (hostName.equalsIgnoreCase(host))
			{
				isLocalHost = true;
			}			
			hostName = java.net.InetAddress.getLocalHost().getHostAddress();
			localHostAliases.add(hostName);
			if (hostName.equalsIgnoreCase(host))
			{
				isLocalHost = true;
			}			
			if (localHostAliases.size() <= 1)
			{
				System.err.println("Unable to determine local host name or address");
			}
			if (isLocalHost)
			{
				if (!host.equals("localhost"))
				{
					System.err.println("Using host:" + host + " which is the local host");
				}
			}
		}
		catch(Exception e)
		{
			System.out.println("Error: reading HOSTs.cfg file");
			e.printStackTrace();
		}
	}
	public void checkDBConnect()
	{
		if (!DBConn.checkMysqlServer(host, user, pass))
		{
			System.err.println("Could not connect to MySQL server using the information in HOSTS.cfg");
			if (!isLocalHost)
			{
				System.err.println("The host (" + host + ") does not appear to be an alias of localhost");
				System.err.println("known aliases are:");
				for (String alias : localHostAliases)
				{
					System.err.println(alias);
				}
				System.exit(0);
			}
			else
			{
				// Try all the aliases
				System.err.println("Trying other aliases for localhost");
				for (String alias : localHostAliases)
				{
					if (DBConn.checkMysqlServer(alias, user, pass))
					{
						System.err.println(alias + ": success!!");
						System.err.println("Using hostname:" + alias);
						host = alias;
						return;
					}
					else
					{
						System.err.println(alias + ": fail");
					}
				}
			}
			System.exit(0);
		}
		System.err.println("Connected to the MySQL database on " + host);
	}
	public boolean checkDBConnect(String db)
	{
		return DBConn.checkMysqlDB("Check DB connection ", host, db, user, pass);

	}
   public String getDbiStr(String db)
   {
	   return "dbi:mysql:" + db + ":" + host;
   }
   public String getJdbcStr(String db)
   {
	   return "jdbc:mysql://" + host + "/" + db;
   }
	public DBConn getDBConn(String db)
	{
		try
		{
			if (!db.trim().equals("") && !db.trim().equals("mysql"))
			{
				return new DBConn(host,db,user,pass);
			}
			else
			{
				return new DBConn(host, user, pass);
			}
		}
		catch(Exception e)
		{ 
			System.err.println("Unable to connect to database!! Exiting");
			e.printStackTrace();
		}
		return null;
	}
	private void getBlastPath() 
	{
	    String bpath = "", dpath="", upath="";
	    
		if (otherParams.containsKey("blast_path"))
		{
			bpath = otherParams.get("blast_path");
			if (bpath.endsWith("/")) bpath = bpath.substring(0, bpath.length()-1);
		}
		if (otherParams.containsKey("diamond_path"))
		{
			dpath = otherParams.get("diamond_path");
			if (dpath.endsWith("/")) dpath = dpath.substring(0, dpath.length()-1); 
		}
		if (otherParams.containsKey("usearch_path"))
		{
			upath = otherParams.get("usearch_path");
			if (upath.endsWith("/")) upath = upath.substring(0, upath.length()-1); 
		}
		BlastArgs.evalBlastPath(bpath, dpath, upath);
	}
	
	public String getCapPath() 
	{
		if (otherParams.containsKey("cap3_path"))
		{
			return otherParams.get("cap3_path");
		}
		return "";
	}
	public String getPhrapPath() 
	{
		if (otherParams.containsKey("phrap_path"))
		{
			return otherParams.get("phrap_path");
		}
		return "";
	}
	public static String getHostName() throws Exception
	{
		String name = getEnv("HOSTNAME");
		if (true)//name.equals(""))
		{
            Process p = Runtime.getRuntime().exec("uname -n");
            BufferedReader stdInput = new BufferedReader(new 
                 InputStreamReader(p.getInputStream()));
            name = stdInput.readLine().trim();       
            p.destroy();			
		}
		return name;
	}
	static String getEnv(String key)
	{
		if (System.getenv().containsKey(key))
		{
			return System.getenv(key);
		}
		return "";
	}
}
